// Main script for module 'Tween'

_TweenData _tweens[MAX_TWEENS];

///////////////////////////////////////////////////////////////////////////////

int GetRFromColor(int color) {
  float floatColor = IntToFloat(color);
  int result = FloatToInt(floatColor / 2048.0) * 8;  
  return result;
}

int GetGFromColor(int color) {
  float floatColor = IntToFloat(color);
  int result = FloatToInt(( floatColor - IntToFloat(FloatToInt(floatColor / 2048.0) * 2048)) / 64.0) * 8;  
  return result;
}

int GetBFromColor(int color) {  
  float floatColor = IntToFloat(color);
  float withoutR = floatColor - IntToFloat(FloatToInt(floatColor / 2048.0) * 2048);
  int withoutRInt = FloatToInt(withoutR);
  float withoutG = withoutR - IntToFloat(FloatToInt(withoutR / 64.0) * 64); 
  int withoutGInt = FloatToInt(withoutG);
  int result = withoutGInt * 8;
  
  if (result > 255) {
    result = (withoutGInt - 31) * 8 - 1;
  }
    
  return result;  
}

int SecondsToLoops(float timeInSeconds) {
  return FloatToInt(IntToFloat(GetGameSpeed()) * timeInSeconds, eRoundNearest);
}

int Lerp(int from, int to, float amount) {
  return FloatToInt(IntToFloat(from) + IntToFloat(to - from) * amount, eRoundUp);
}

float ComputeTiming(int currentTime, int duration, TweenTiming timingType) {
	float timing = IntToFloat(currentTime) / IntToFloat(duration);
	
	if (timingType != eLinearTween) {
	  float timing2 = Maths.RaiseToPower(timing, 2.0);
	  
		if (timingType == eEaseInTween) {
		  timing = ((3.0 * timing2) - (timing2 * timing)) * 0.5;
		}
		else if (timingType == eEaseOutTween) {
		  timing = ((3.0 * timing) - (timing2 * timing)) * 0.5;
		}
		else if (timingType == eEaseInEaseOutTween) {
		  timing = (3.0 * timing2) - (2.0 * timing * timing2);
		}
	}
	
	return timing;
}

///////////////////////////////////////////////////////////////////////////////

int NewTween1(_TweenType type, float timeInSeconds, short toX, short toY, short fromX, short fromY, short extraParam1, 
						GUI* guiRef, Object* objectRef, Character* characterRef, Region* regionRef,  Label* labelRef, 
            TweenTiming timing, TweenStyle style) {
	
	short i = 0;
	short spotAvailable = -1;
	
	while (i < MAX_TWEENS && spotAvailable == -1) {
	  if (_tweens[i].duration == -1) {
			spotAvailable = i;
		}
	  
	  i++;
  }
  
  if (spotAvailable != -1) {
    _tweens[spotAvailable].type = type;
		_tweens[spotAvailable].guiRef = guiRef;
		_tweens[spotAvailable].objectRef = objectRef;   
		_tweens[spotAvailable].characterRef = characterRef;
    _tweens[spotAvailable].regionRef = regionRef;
    _tweens[spotAvailable].labelRef = labelRef;
		_tweens[spotAvailable].toX = toX;
		_tweens[spotAvailable].toY = toY;
		_tweens[spotAvailable].fromX = fromX;
		_tweens[spotAvailable].fromY = fromY;
    _tweens[spotAvailable].extraParam1 = extraParam1;
		_tweens[spotAvailable].duration = SecondsToLoops(timeInSeconds);
		_tweens[spotAvailable].frameCount = 0;
		_tweens[spotAvailable].timing = timing;
		_tweens[spotAvailable].style = style;
		
		if (_tweens[spotAvailable].style == eBlockTween) {
		  Wait(_tweens[spotAvailable].duration + 1);
		}
		else {
			return _tweens[spotAvailable].duration + 1;
		}
  }
#ifdef DEBUG
  else {
    AbortGame("Cannot create new tween because the Tween module is currently playing %d tween(s), which is the maximum. You can increase this max number on the Tween module script header.", MAX_TWEENS);
  }
#endif
  

	return 1;	
}

int NewTween2(_TweenType type, float timeInSeconds, short toX, short toY, short fromX, short fromY, short extraParam1, 						 
            Button* buttonRef, TextBox* textBoxRef, ListBox* listBoxRef, Slider* sliderRef, InvWindow* invWindowRef, TweenTiming timing, TweenStyle style) {
	
	short i = 0;
	short spotAvailable = -1;
	
	while (i < MAX_TWEENS && spotAvailable == -1) {
	  if (_tweens[i].duration == -1) {
			spotAvailable = i;
		}
	  
	  i++;
  }
  
  if (spotAvailable != -1) {
    _tweens[spotAvailable].type = type;
		_tweens[spotAvailable].buttonRef = buttonRef;
		_tweens[spotAvailable].textBoxRef = textBoxRef;   
		_tweens[spotAvailable].listBoxRef = listBoxRef;
    _tweens[spotAvailable].sliderRef = sliderRef;
    _tweens[spotAvailable].invWindowRef = invWindowRef;
		_tweens[spotAvailable].toX = toX;
		_tweens[spotAvailable].toY = toY;
		_tweens[spotAvailable].fromX = fromX;
		_tweens[spotAvailable].fromY = fromY;
    _tweens[spotAvailable].extraParam1 = extraParam1;
		_tweens[spotAvailable].duration = SecondsToLoops(timeInSeconds);
		_tweens[spotAvailable].frameCount = 0;
		_tweens[spotAvailable].timing = timing;
		_tweens[spotAvailable].style = style;
		
		if (_tweens[spotAvailable].style == eBlockTween) {
		  Wait(_tweens[spotAvailable].duration + 1);
		}
		else {
			return _tweens[spotAvailable].duration + 1;
		}
  }
#ifdef DEBUG
  else {
    AbortGame("Cannot create new tween because the Tween module is currently playing %d tween(s), which is the maximum. You can increase this max number on the Tween module script header.", MAX_TWEENS);
  }
#endif
  

	return 1;	
}

int NewGUITween(_TweenType type, float timeInSeconds, short toX, short toY, short fromX, short fromY, short extraParam1, 
    GUI* guiRef, TweenTiming timing, TweenStyle style) {
  return NewTween1(type, timeInSeconds, toX, toY, fromX, fromY, extraParam1, guiRef, null, null, null, null, 
  timing, style);
}

int NewObjectTween(_TweenType type, float timeInSeconds, short toX, short toY, short fromX, short fromY, short extraParam1, 
    Object* objectRef, TweenTiming timing, TweenStyle style) {
  return NewTween1(type, timeInSeconds, toX, toY, fromX, fromY, extraParam1, null, objectRef, null, null, null, 
  timing, style);
}

int NewCharacterTween(_TweenType type, float timeInSeconds, short toX, short toY, short fromX, short fromY, short extraParam1, 
    Character* characterRef, TweenTiming timing, TweenStyle style) {
  return NewTween1(type, timeInSeconds, toX, toY, fromX, fromY, extraParam1, null, null, characterRef, null, null, 
  timing, style);
}

int NewRegionTween(_TweenType type, float timeInSeconds, short toX, short toY, short fromX, short fromY, short extraParam1, 
    Region* regionRef, TweenTiming timing, TweenStyle style) {
  return NewTween1(type, timeInSeconds, toX, toY, fromX, fromY, extraParam1, null, null, null, regionRef, null, 
  timing, style);
}

int NewLabelTween(_TweenType type, float timeInSeconds, short toX, short toY, short fromX, short fromY, short extraParam1, 
    Label* labelRef, TweenTiming timing, TweenStyle style) {
  return NewTween1(type, timeInSeconds, toX, toY, fromX, fromY, extraParam1, null, null, null, null, labelRef, 
  timing, style);
}

int NewButtonTween(_TweenType type, float timeInSeconds, short toX, short toY, short fromX, short fromY, short extraParam1, 
    Button* buttonRef, TweenTiming timing, TweenStyle style) {
  return NewTween2(type, timeInSeconds, toX, toY, fromX, fromY, extraParam1, 
  buttonRef, null, null, null, null, timing, style);
}

int NewTextBoxTween(_TweenType type, float timeInSeconds, short toX, short toY, short fromX, short fromY, short extraParam1, 
    TextBox* textBoxRef, TweenTiming timing, TweenStyle style) {
  return NewTween2(type, timeInSeconds, toX, toY, fromX, fromY, extraParam1,  
  null, textBoxRef, null, null, null, timing, style);
}

int NewListBoxTween(_TweenType type, float timeInSeconds, short toX, short toY, short fromX, short fromY, short extraParam1, 
    ListBox* listBoxRef, TweenTiming timing, TweenStyle style) {
  return NewTween2(type, timeInSeconds, toX, toY, fromX, fromY, extraParam1,  
  null, null, listBoxRef, null, null, timing, style);
}

int NewSliderTween(_TweenType type, float timeInSeconds, short toX, short toY, short fromX, short fromY, short extraParam1, 
    Slider* sliderRef, TweenTiming timing, TweenStyle style) {
  return NewTween2(type, timeInSeconds, toX, toY, fromX, fromY, extraParam1, 
  null, null, null, sliderRef, null, timing, style);
}

int NewInvWindowTween(_TweenType type, float timeInSeconds, short toX, short toY, short fromX, short fromY, short extraParam1, 
    InvWindow* invWindowRef, TweenTiming timing, TweenStyle style) {
  return NewTween2(type, timeInSeconds, toX, toY, fromX, fromY, extraParam1,  
  null, null, null, null, invWindowRef, timing, style);
}

int NewMiscTween(_TweenType type, float timeInSeconds, short toX, short toY, short fromX, short fromY, short extraParam1, 
    TweenTiming timing, TweenStyle style) {
  return NewTween2(type, timeInSeconds, toX, toY, fromX, fromY, extraParam1, 
  null, null, null, null, null, timing, style);
}

int TweenGUIPosition(GUI* guiRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {
  return NewGUITween(_eTweenGUIPosition,  timeInSeconds, toX, toY, guiRef.X, guiRef.Y, 0, guiRef, timing, style);
}

int TweenGUIZOrder(GUI* guiRef, float timeInSeconds, short toZOrder, TweenTiming timing, TweenStyle style) {
  return NewGUITween(_eTweenGUIZOrder, timeInSeconds, toZOrder, 0, guiRef.ZOrder, 0, 0, guiRef, timing, style);
}

int TweenGUITransparency(GUI* guiRef, float timeInSeconds, short toTransparency, TweenTiming timing, TweenStyle style) {
	return NewGUITween(_eTweenGUITransparency, timeInSeconds, toTransparency, 0, guiRef.Transparency, 0, 0, guiRef, timing, style);
}

int TweenGUISize(GUI* guiRef, float timeInSeconds, short toWidth, short toHeight, TweenTiming timing, TweenStyle style) {
	return NewGUITween(_eTweenGUISize, timeInSeconds, toWidth, toHeight, guiRef.Width, guiRef.Height, 0, guiRef, timing, style);
}

int TweenObjectPosition(Object* objectRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {
	return NewObjectTween(_eTweenObjectPosition, timeInSeconds, toX, toY, objectRef.X, objectRef.Y,  0, objectRef, timing, style);
}

int TweenObjectTransparency(Object* objectRef, float timeInSeconds, short toTransparency, TweenTiming timing, TweenStyle style) {
	return NewObjectTween(_eTweenObjectTransparency, timeInSeconds, toTransparency, 0, objectRef.Transparency, 0, 0, objectRef, timing, style);
}

int TweenObjectImage(Object* objectRef, Object* tmpObjectRef, float timeInSeconds,  short toSprite,  TweenTiming timing, TweenStyle style) {      
  tmpObjectRef.Graphic = objectRef.Graphic;
  tmpObjectRef.SetPosition(objectRef.X, objectRef.Y);
  tmpObjectRef.Transparency = 0;
  tmpObjectRef.Visible = true;
  
  objectRef.Transparency = 100;
  objectRef.Graphic = toSprite;  
  
  if (style == eBlockTween) {
    TweenObjectTransparency(tmpObjectRef, timeInSeconds, 100, timing, eNoBlockTween);
  }
  else {
    TweenObjectTransparency(tmpObjectRef, timeInSeconds, 100, timing, style);
  }
  return TweenObjectTransparency(objectRef, timeInSeconds, 0, timing, style);  
}

int TweenCharacterPosition(Character* characterRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {
  return NewCharacterTween(_eTweenCharacterPosition, timeInSeconds, toX, toY, characterRef.x, characterRef.y, 0, characterRef, timing, style);
}

int TweenCharacterScaling(Character* characterRef, float timeInSeconds, short toScaling, TweenTiming timing, TweenStyle style) {
	if (!characterRef.ManualScaling) {
		characterRef.ManualScaling = true;
	}
	  
  return NewCharacterTween(_eTweenCharacterScaling, timeInSeconds, toScaling, 0, characterRef.Scaling, 0, 0, characterRef, timing, style);
}

int TweenCharacterTransparency(Character* characterRef, float timeInSeconds, short toTransparency, TweenTiming timing, TweenStyle style) {
  return NewCharacterTween(_eTweenCharacterTransparency, timeInSeconds, toTransparency, 0, characterRef.Transparency, 0, 0, characterRef, timing, style);
}

int TweenCharacterAnimationSpeed(Character* characterRef, float timeInSeconds, short toAnimationSpeed, TweenTiming timing, TweenStyle style) {
  return NewCharacterTween(_eTweenCharacterAnimationSpeed, timeInSeconds, toAnimationSpeed, 0, characterRef.AnimationSpeed, 0, 0, characterRef, timing, style);
} 

int TweenRegionLightLevel(Region* regionRef, float timeInSeconds, short toLightLevel, TweenTiming timing, TweenStyle style) {
  return NewRegionTween(_eTweenRegionLightLevel, timeInSeconds, toLightLevel, 0, regionRef.LightLevel, 0, 0, regionRef, timing, style);  
}  

int TweenRegionTintR(Region* regionRef, float timeInSeconds, short toR, TweenTiming timing, TweenStyle style) {
  return NewRegionTween(_eTweenRegionTintR, timeInSeconds, toR, 0, regionRef.TintRed, 0, 0, regionRef, timing, style);  
}  

int TweenRegionTintG(Region* regionRef, float timeInSeconds, short toG, TweenTiming timing, TweenStyle style) {
  return NewRegionTween(_eTweenRegionTintG, timeInSeconds, toG, 0, regionRef.TintGreen, 0, 0, regionRef, timing, style);  
} 

int TweenRegionTintB(Region* regionRef, float timeInSeconds, short toB, TweenTiming timing, TweenStyle style) {
  return NewRegionTween(_eTweenRegionTintB, timeInSeconds, toB, 0, regionRef.TintBlue, 0, 0, regionRef, timing, style);  
} 

int TweenRegionTintAmount(Region* regionRef, float timeInSeconds, short toAmount, TweenTiming timing, TweenStyle style) {
  return NewRegionTween(_eTweenRegionTintAmount, timeInSeconds, toAmount, 0, regionRef.TintSaturation, 0, 0, regionRef, timing, style);  
} 

int TweenRegionTintBlackAndWhite(Region* regionRef, float timeInSeconds, TweenTiming timing, TweenStyle style) {
  if (style == eBlockTween) {
    TweenRegionTintR(regionRef, timeInSeconds, 255, timing, eNoBlockTween);
    TweenRegionTintG(regionRef, timeInSeconds, 255, timing, eNoBlockTween);
    TweenRegionTintB(regionRef, timeInSeconds, 255, timing, eNoBlockTween);
  }
  else {
    TweenRegionTintR(regionRef, timeInSeconds, 255, timing, style);
    TweenRegionTintG(regionRef, timeInSeconds, 255, timing, style);
    TweenRegionTintB(regionRef, timeInSeconds, 255, timing, style);
  }
  return TweenRegionTintAmount(regionRef, timeInSeconds, 100, timing, style);
}


int TweenLabelPosition(Label* labelRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return NewLabelTween(_eTweenLabelPosition, timeInSeconds, toX, toY, labelRef.X, labelRef.Y, 0, labelRef, timing, style);
}

int TweenLabelSize(Label* labelRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return NewLabelTween(_eTweenLabelSize, timeInSeconds, toX, toY, labelRef.Width, labelRef.Height, 0, labelRef, timing, style);
}

int TweenLabelColorR(Label* labelRef, float timeInSeconds, short toR, TweenTiming timing, TweenStyle style) {
  int fromR = GetRFromColor(labelRef.TextColor);
  return NewLabelTween(_eTweenLabelColorR, timeInSeconds, toR, 0, fromR, 0, 0, labelRef, timing, style);
}
int TweenLabelColorG(Label* labelRef, float timeInSeconds, short toG, TweenTiming timing, TweenStyle style) {
  int fromG = GetGFromColor(labelRef.TextColor);
  return NewLabelTween(_eTweenLabelColorG, timeInSeconds, toG, 0, fromG, 0, 0, labelRef, timing, style);
}
int TweenLabelColorB(Label* labelRef, float timeInSeconds, short toB, TweenTiming timing, TweenStyle style) {
  int fromB = GetBFromColor(labelRef.TextColor);
  return NewLabelTween(_eTweenLabelColorB, timeInSeconds, toB, 0, fromB, 0, 0, labelRef, timing, style);
}

int TweenButtonPosition(Button* buttonRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return NewButtonTween(_eTweenButtonPosition, timeInSeconds, toX, toY, buttonRef.X, buttonRef.Y, 0, buttonRef, timing, style);
}
int TweenButtonSize(Button* buttonRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return NewButtonTween(_eTweenButtonSize, timeInSeconds, toX, toY, buttonRef.Width, buttonRef.Height, 0, buttonRef, timing, style);
}
int TweenButtonColorR(Button* buttonRef, float timeInSeconds, short toR, TweenTiming timing, TweenStyle style) {
  int fromR = GetRFromColor(buttonRef.TextColor);
  return NewButtonTween(_eTweenButtonColorR, timeInSeconds, toR, 0, fromR, 0, 0, buttonRef, timing, style);
}
int TweenButtonColorG(Button* buttonRef, float timeInSeconds, short toG, TweenTiming timing, TweenStyle style) {
  int fromG = GetGFromColor(buttonRef.TextColor);
  return NewButtonTween(_eTweenButtonColorG, timeInSeconds, toG, 0, fromG, 0, 0, buttonRef, timing, style);
}
int TweenButtonColorB(Button* buttonRef, float timeInSeconds, short toB, TweenTiming timing, TweenStyle style) {
  int fromB = GetBFromColor(buttonRef.TextColor);
  return NewButtonTween(_eTweenButtonColorB, timeInSeconds, toB, 0, fromB, 0, 0, buttonRef, timing, style);
}

int TweenTextBoxPosition(TextBox* textBoxRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return NewTextBoxTween(_eTweenTextBoxPosition, timeInSeconds, toX, toY, textBoxRef.X, textBoxRef.Y, 0, textBoxRef, timing, style);
}
int TweenTextBoxSize(TextBox* textBoxRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return NewTextBoxTween(_eTweenTextBoxSize, timeInSeconds, toX, toY, textBoxRef.Width, textBoxRef.Height, 0, textBoxRef, timing, style);
}
int TweenTextBoxColorR(TextBox* textBoxRef, float timeInSeconds, short toR, TweenTiming timing, TweenStyle style) {
  int fromR = GetRFromColor(textBoxRef.TextColor);
  return NewTextBoxTween(_eTweenTextBoxColorR, timeInSeconds, toR, 0, fromR, 0, 0, textBoxRef, timing, style);
}
int TweenTextBoxColorG(TextBox* textBoxRef, float timeInSeconds, short toG, TweenTiming timing, TweenStyle style) {
  int fromG = GetGFromColor(textBoxRef.TextColor);
  return NewTextBoxTween(_eTweenTextBoxColorG, timeInSeconds, toG, 0, fromG, 0, 0, textBoxRef, timing, style);
}
int TweenTextBoxColorB(TextBox* textBoxRef, float timeInSeconds, short toB, TweenTiming timing, TweenStyle style) {
  int fromB = GetBFromColor(textBoxRef.TextColor);
  return NewTextBoxTween(_eTweenTextBoxColorB, timeInSeconds, toB, 0, fromB, 0, 0, textBoxRef, timing, style);
}

int TweenListBoxPosition(ListBox* listBoxRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return NewListBoxTween(_eTweenListBoxPosition, timeInSeconds, toX, toY, listBoxRef.X, listBoxRef.Y, 0, listBoxRef, timing, style);
}
int TweenListBoxSize(ListBox* listBoxRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return NewListBoxTween(_eTweenListBoxSize, timeInSeconds, toX, toY, listBoxRef.Width, listBoxRef.Height, 0, listBoxRef, timing, style);
}
int TweenListBoxSelectedItem(ListBox* listBoxRef, float timeInSeconds, short toSelectedItem, TweenTiming timing, TweenStyle style) {  
  return NewListBoxTween(_eTweenListBoxSelectedItem, timeInSeconds, toSelectedItem, 0, listBoxRef.SelectedIndex, 0, 0, listBoxRef, timing, style);
}
int TweenListBoxTopItem(ListBox* listBoxRef, float timeInSeconds, short toTopItem, TweenTiming timing, TweenStyle style) {  
  return NewListBoxTween(_eTweenListBoxTopItem, timeInSeconds, toTopItem, 0, listBoxRef.TopItem, 0, 0, listBoxRef, timing, style);
}

int TweenSliderPosition(Slider* sliderRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return NewSliderTween(_eTweenSliderPosition, timeInSeconds, toX, toY, sliderRef.X, sliderRef.Y, 0, sliderRef, timing, style);
}
int TweenSliderSize(Slider* sliderRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return NewSliderTween(_eTweenSliderSize, timeInSeconds, toX, toY, sliderRef.Width, sliderRef.Height, 0, sliderRef, timing, style);
}
int TweenSliderValue(Slider* sliderRef, float timeInSeconds, short toValue, TweenTiming timing, TweenStyle style) {  
  return NewSliderTween(_eTweenSliderValue, timeInSeconds, toValue, 0, sliderRef.Value, 0, 0, sliderRef, timing, style);
}
int TweenSliderHandleOffset(Slider* sliderRef, float timeInSeconds, short toHandleOffset, TweenTiming timing, TweenStyle style) {  
  return NewSliderTween(_eTweenSliderHandleOffset, timeInSeconds, toHandleOffset, 0, sliderRef.HandleOffset, 0, 0, sliderRef, timing, style);
}

int TweenInvWindowPosition(InvWindow* invWindowRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return NewInvWindowTween(_eTweenInvWindowPosition, timeInSeconds, toX, toY, invWindowRef.X, invWindowRef.Y, 0, invWindowRef, timing, style);
}
int TweenInvWindowSize(InvWindow* invWindowRef, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return NewInvWindowTween(_eTweenInvWindowSize, timeInSeconds, toX, toY, invWindowRef.Width, invWindowRef.Height, 0, invWindowRef, timing, style);
}
int TweenInvWindowTopItem(InvWindow* invWindowRef, float timeInSeconds, short toTopItem, TweenTiming timing, TweenStyle style) {  
  return NewInvWindowTween(_eTweenInvWindowTopItem, timeInSeconds, toTopItem, 0, invWindowRef.TopItem, 0, 0, invWindowRef, timing, style);
}

int TweenViewportX(float timeInSeconds, short toX, TweenTiming timing,  TweenStyle style) {
  return NewMiscTween(_eTweenViewportX, timeInSeconds, toX, 0, GetViewportX(), 0, 0, timing,  style); 
}

int TweenViewportY(float timeInSeconds, short toY, TweenTiming timing,  TweenStyle style) {  
  return NewMiscTween(_eTweenViewportY, timeInSeconds, 0, toY, 0, GetViewportY(), 0, timing,  style); 
}

int TweenViewportXY(float timeInSeconds, short toX,  short toY, TweenTiming timing,  TweenStyle style) {  
  return NewMiscTween(_eTweenViewportXY, timeInSeconds, toX, toY, GetViewportX(), GetViewportY(), 0, timing,  style); 
}

int TweenGamma(float timeInSeconds, short toGamma, TweenTiming timing, TweenStyle style) {
  return NewMiscTween(_eTweenGamma,  timeInSeconds, toGamma, 0, System.Gamma,  0, 0, timing, style); 
}

int TweenShakeScreen(float timeInSeconds, short fromDelay, short toDelay, short fromAmount, short toAmount, TweenTiming timing, TweenStyle style) {
  return NewMiscTween(_eTweenShakeScreen, timeInSeconds,   toDelay, toAmount, fromDelay, fromAmount, 0, timing, style);
}  

int TweenMusicMasterVolume(float timeInSeconds, short fromVolume, short toVolume, TweenTiming timing,  TweenStyle style) {
  return NewMiscTween(_eTweenMusicMasterVolume, timeInSeconds, toVolume, 0, fromVolume, 0, 0, timing, style);
}  
int TweenDigitalMasterVolume(float timeInSeconds, short fromVolume, short toVolume, TweenTiming timing, TweenStyle style) {
   return NewMiscTween(_eTweenDigitalMasterVolume, timeInSeconds,  toVolume, 0, fromVolume, 0, 0, timing, style);
}  
int TweenSpeechVolume(float timeInSeconds, short fromVolume, short toVolume, TweenTiming timing,  TweenStyle style) {
  return NewMiscTween(_eTweenSpeechVolume, timeInSeconds, toVolume, 0, fromVolume, 0, 0, timing, style);
}  
int TweenSoundVolume(float timeInSeconds, short fromVolume, short toVolume, TweenTiming timing, TweenStyle style) {
   return NewMiscTween(_eTweenSoundVolume, timeInSeconds,  toVolume, 0, fromVolume, 0, 0, timing, style);
}  
int TweenChannelVolume(float timeInSeconds, short channel, short fromVolume, short toVolume, TweenTiming timing, TweenStyle style) {
   return NewMiscTween(_eTweenChannelVolume, timeInSeconds,  toVolume, 0, fromVolume, 0, channel, timing, style);
}  

int TweenAreaScaling(float timeInSeconds, short area, short fromMin, short toMin, short fromMax, short toMax, TweenTiming timing, TweenStyle style) {
   return NewMiscTween(_eTweenAreaScaling, timeInSeconds, toMin, toMax, fromMin, fromMax, area, timing, style);
}

void TweenStopAllForGUI(GUI* guiRef) {
  short i = 0;
  
	while (i < MAX_TWEENS) {
	  if (_tweens[i].guiRef == guiRef) {
			_tweens[i].duration = -1;
    }
    
		i++;
	}
}

void TweenStopAllForObject(Object* objectRef) {
  short i = 0;
  
	while (i < MAX_TWEENS) {
	  if (_tweens[i].objectRef == objectRef) {
			_tweens[i].duration = -1;
    }
    
		i++;
	}
}

void TweenStopAllForCharacter(Character* characterRef) {
  short i = 0;
  
	while (i < MAX_TWEENS) {
	  if (_tweens[i].characterRef == characterRef) {
			_tweens[i].duration = -1;
    }
    
		i++;
	}
}

void TweenStopAllForRegion(Region* regionRef) {
  short i = 0;
  
	while (i < MAX_TWEENS) {
	  if (_tweens[i].regionRef == regionRef) {
			_tweens[i].duration = -1;
    }
    
		i++;
	}
}

void TweenStopAllForLabel(Label* labelRef) {
  short i = 0;
  
	while (i < MAX_TWEENS) {
	  if (_tweens[i].labelRef == labelRef) {
			_tweens[i].duration = -1;
    }
    
		i++;
	}
}
void TweenStopAllForButton(Button* buttonRef) {
  short i = 0;
  
	while (i < MAX_TWEENS) {
	  if (_tweens[i].buttonRef == buttonRef) {
			_tweens[i].duration = -1;
    }
    
		i++;
	}
}
void TweenStopAllForTextBox(TextBox* textBoxRef) {
  short i = 0;
  
	while (i < MAX_TWEENS) {
	  if (_tweens[i].textBoxRef == textBoxRef) {
			_tweens[i].duration = -1;
    }
    
		i++;
	}
}
void TweenStopAllForListBox(ListBox* listBoxRef) {
  short i = 0;
  
	while (i < MAX_TWEENS) {
	  if (_tweens[i].listBoxRef == listBoxRef) {
			_tweens[i].duration = -1;
    }
    
		i++;
	}
}
void TweenStopAllForSlider(Slider* sliderRef) {
  short i = 0;
  
	while (i < MAX_TWEENS) {
	  if (_tweens[i].sliderRef == sliderRef) {
			_tweens[i].duration = -1;
    }
    
		i++;
	}
}
void TweenStopAllForInvWindow(InvWindow* invWindowRef) {
  short i = 0;
  
	while (i < MAX_TWEENS) {
	  if (_tweens[i].invWindowRef == invWindowRef) {
			_tweens[i].duration = -1;
    }
    
		i++;
	}
}

void TweenStopAll() {
  short i = 0;
  
  while (i < MAX_TWEENS) {
    _tweens[i].duration = -1;
    i++;
  }
}

///////////////////////////////////////////////////////////////////////////////
// FOR AGS 3.0 OR LATER ONLY
///////////////////////////////////////////////////////////////////////////////

#ifdef AGS_SUPPORTS_IFVER
#ifver 3.0
int TweenPosition(this GUI*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {
  return TweenGUIPosition(this, timeInSeconds, toX, toY, timing, style);
}

int TweenPosition(this Object*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {
  return TweenObjectPosition(this, timeInSeconds, toX, toY, timing, style);
}

int TweenPosition(this Character*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {
  return TweenCharacterPosition(this, timeInSeconds, toX, toY, timing, style);
}

int TweenPosition(this Label*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return TweenLabelPosition(this, timeInSeconds, toX, toY, timing, style);
}

int TweenPosition(this Button*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return TweenButtonPosition(this, timeInSeconds, toX, toY, timing, style);
}

int TweenPosition(this TextBox*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return TweenTextBoxPosition(this, timeInSeconds, toX, toY, timing, style);
}

int TweenPosition(this ListBox*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return TweenListBoxPosition(this, timeInSeconds, toX, toY, timing, style);
}

int TweenPosition(this Slider*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return TweenSliderPosition(this, timeInSeconds, toX, toY, timing, style);
}

int TweenPosition(this InvWindow*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return TweenInvWindowPosition(this, timeInSeconds, toX, toY, timing, style);
}

int TweenTransparency(this GUI*, float timeInSeconds, short toTransparency, TweenTiming timing, TweenStyle style) {
  return TweenGUITransparency(this, timeInSeconds, toTransparency, timing, style);
}

int TweenTransparency(this Object*, float timeInSeconds, short toTransparency, TweenTiming timing, TweenStyle style) {
  return TweenObjectTransparency(this, timeInSeconds, toTransparency, timing, style);
}

int TweenTransparency(this Character*, float timeInSeconds, short toTransparency, TweenTiming timing, TweenStyle style) {
  return TweenCharacterTransparency(this, timeInSeconds, toTransparency, timing, style);
}

int TweenZOrder(this GUI*, float timeInSeconds, short toZOrder, TweenTiming timing, TweenStyle style) {
  return TweenGUIZOrder(this, timeInSeconds, toZOrder, timing, style); 
}  

int TweenImage(this Object*,  Object* tmpObjectRef, float timeInSeconds,  short toSprite,  TweenTiming timing, TweenStyle style) {
  return TweenObjectImage(this, tmpObjectRef,  timeInSeconds, toSprite, timing, style);
}

int TweenAnimationSpeed(this Character*, float timeInSeconds, short toAnimationSpeed, TweenTiming timing, TweenStyle style) {
  return TweenCharacterAnimationSpeed(this, timeInSeconds, toAnimationSpeed, timing, style);
} 

void StopAllTweens(this GUI*) {
  TweenStopAllForGUI(this);
}

void StopAllTweens(this Object*) {
  TweenStopAllForObject(this);
}

void StopAllTweens(this Character*) {
  TweenStopAllForCharacter(this);
}

void StopAllTweens(this Region*) {
  TweenStopAllForRegion(this);
}

void StopAllTweens(this Label*) {
  TweenStopAllForLabel(this);
}

void StopAllTweens(this Button*) {
  TweenStopAllForButton(this);
}

void StopAllTweens(this TextBox*) {
  TweenStopAllForTextBox(this);
}

void StopAllTweens(this ListBox*) {
  TweenStopAllForListBox(this);
}

void StopAllTweens(this Slider*) {
  TweenStopAllForSlider(this);
}

void StopAllTweens(this InvWindow*) {
  TweenStopAllForInvWindow(this);
}

int TweenSize(this GUI*, float timeInSeconds, short toWidth, short toHeight, TweenTiming timing, TweenStyle style) {
  return TweenGUISize(this, timeInSeconds, toWidth, toHeight, timing, style);
}

int TweenSize(this Label*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return TweenLabelSize(this, timeInSeconds, toX, toY, timing, style);
}

int TweenSize(this Button*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return TweenButtonSize(this, timeInSeconds, toX, toY, timing, style);
}

int TweenSize(this TextBox*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return TweenTextBoxSize(this, timeInSeconds, toX, toY, timing, style);
}

int TweenSize(this ListBox*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return TweenListBoxSize(this, timeInSeconds, toX, toY, timing, style);
}

int TweenSize(this Slider*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return TweenSliderSize(this, timeInSeconds, toX, toY, timing, style);
}

int TweenSize(this InvWindow*, float timeInSeconds, short toX, short toY, TweenTiming timing, TweenStyle style) {  
  return TweenInvWindowSize(this, timeInSeconds, toX, toY, timing, style);
}

int TweenScaling(this Character*, float timeInSeconds, short toScaling, TweenTiming timing, TweenStyle style) {
  return TweenCharacterScaling(this, timeInSeconds, toScaling, timing, style);
}

int TweenLightLevel(this Region*, float timeInSeconds, short toLightLevel, TweenTiming timing, TweenStyle style) {
  return TweenRegionLightLevel(this, timeInSeconds, toLightLevel, timing, style); 
}  

int TweenTintR(this Region*, float timeInSeconds, short toR, TweenTiming timing, TweenStyle style) {
  return TweenRegionTintR(this, timeInSeconds, toR, timing, style);  
}  

int TweenTintG(this Region*, float timeInSeconds, short toG, TweenTiming timing, TweenStyle style) {
  return TweenRegionTintG(this, timeInSeconds, toG, timing, style);  
} 

int TweenTintB(this Region*, float timeInSeconds, short toB, TweenTiming timing, TweenStyle style) {
  return TweenRegionTintB(this, timeInSeconds, toB, timing, style);  
} 

int TweenTintAmount(this Region*, float timeInSeconds, short toAmount, TweenTiming timing, TweenStyle style) {
  return TweenRegionTintAmount(this, timeInSeconds, toAmount, timing, style);  
} 

int TweenTintBlackAndWhite(this Region*, float timeInSeconds, TweenTiming timing, TweenStyle style) {
  return TweenRegionTintBlackAndWhite(this, timeInSeconds, timing, style);
}

int TweenColorR(this Label*, float timeInSeconds, short toR, TweenTiming timing, TweenStyle style) {
  return TweenLabelColorR(this, timeInSeconds, toR, timing, style);
}
int TweenColorG(this Label*, float timeInSeconds, short toG, TweenTiming timing, TweenStyle style) {
  return TweenLabelColorG(this, timeInSeconds, toG, timing, style);
}
int TweenColorB(this Label*, float timeInSeconds, short toB, TweenTiming timing, TweenStyle style) {
  return TweenLabelColorB(this, timeInSeconds, toB, timing, style);
}
int TweenColorR(this Button*, float timeInSeconds, short toR, TweenTiming timing, TweenStyle style) {
  return TweenButtonColorR(this, timeInSeconds, toR, timing, style);
}
int TweenColorG(this Button*, float timeInSeconds, short toG, TweenTiming timing, TweenStyle style) {
  return TweenButtonColorG(this, timeInSeconds, toG, timing, style);
}
int TweenColorB(this Button*, float timeInSeconds, short toB, TweenTiming timing, TweenStyle style) {
  return TweenButtonColorB(this, timeInSeconds, toB, timing, style);
}
int TweenColorR(this TextBox*, float timeInSeconds, short toR, TweenTiming timing, TweenStyle style) {
  return TweenTextBoxColorR(this, timeInSeconds, toR, timing, style);
}
int TweenColorG(this TextBox*, float timeInSeconds, short toG, TweenTiming timing, TweenStyle style) {
  return TweenTextBoxColorG(this, timeInSeconds, toG, timing, style);
}
int TweenColorB(this TextBox*, float timeInSeconds, short toB, TweenTiming timing, TweenStyle style) {
  return TweenTextBoxColorB(this, timeInSeconds, toB, timing, style);
}

int TweenSelectedItem(this ListBox*, float timeInSeconds, short toSelectedItem, TweenTiming timing, TweenStyle style) {  
  return TweenListBoxSelectedItem(this, timeInSeconds, toSelectedItem, timing, style);
}
int TweenTopItem(this ListBox*, float timeInSeconds, short toTopItem, TweenTiming timing, TweenStyle style) {  
  return TweenListBoxTopItem(this, timeInSeconds, toTopItem, timing, style);
}
int TweenTopItem(this InvWindow*, float timeInSeconds, short toTopItem, TweenTiming timing, TweenStyle style) {  
  return TweenInvWindowTopItem(this, timeInSeconds, toTopItem, timing, style);
}

int TweenValue(this Slider*, float timeInSeconds, short toValue, TweenTiming timing, TweenStyle style) {  
  return TweenSliderValue(this, timeInSeconds, toValue, timing, style);
}
int TweenHandleOffset(this Slider*, float timeInSeconds, short toHandleOffset, TweenTiming timing, TweenStyle style) {  
  return TweenSliderHandleOffset(this, timeInSeconds, toHandleOffset, timing, style);
}

#endif
#endif

///////////////////////////////////////////////////////////////////////////////

function _TweenData::step(float amount) {
  // GUI step
  if (this.type == _eTweenGUIPosition) {
		this.guiRef.SetPosition(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
	}  
	if (this.type == _eTweenGUISize) {
		this.guiRef.SetSize(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
	}
	else if (this.type == _eTweenGUITransparency) {
	  // Workaround for Popup Modal GUIs. If the scripter is fading this in, then make it vsible.
	  if (this.frameCount == 0 && this.guiRef.Visible == false && this.guiRef.Transparency == 100) {
	    this.guiRef.Visible = true;
	  }
	  
		this.guiRef.Transparency = Lerp(this.fromX, this.toX, amount);
		
		// Workaround for Popup Modal GUIs. If the scripter is fading this out, then make it invisble.
		if (this.frameCount == this.duration && this.guiRef.Visible == true && this.guiRef.Transparency == 100) {
			this.guiRef.Visible = false;
		}
	}
  else if (this.type == _eTweenGUIZOrder) {
    this.guiRef.ZOrder = Lerp(this.fromX, this.toX, amount);
  }
	/// OBJECT step
  else if (this.type == _eTweenObjectPosition) {
		this.objectRef.SetPosition(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
	}  
	else if (this.type == _eTweenObjectTransparency) {
	  if (this.frameCount == 0 && this.objectRef.Visible == false && this.objectRef.Transparency == 100) {
	    this.objectRef.Visible = true;
	  }
	  
		this.objectRef.Transparency = Lerp(this.fromX, this.toX, amount);
		
		if (this.frameCount == this.duration && this.objectRef.Visible == true && this.objectRef.Transparency == 100) {
			this.objectRef.Visible = false;
		}
	}	  
	/// CHARACTER step
  else if (this.type == _eTweenCharacterPosition) {    
		this.characterRef.x = Lerp(this.fromX, this.toX, amount);
		this.characterRef.y = Lerp(this.fromY, this.toY, amount);
	}  
	else if (this.type == _eTweenCharacterScaling) {	  
	  this.characterRef.Scaling = Lerp(this.fromX, this.toX, amount);
	}
	else if (this.type == _eTweenCharacterTransparency) { 
		this.characterRef.Transparency = Lerp(this.fromX, this.toX, amount);
	}
  else if (this.type == _eTweenCharacterAnimationSpeed) {
    this.characterRef.AnimationSpeed = Lerp(this.fromX, this.toX, amount);
  }  
  /// REGION step
  else if (this.type == _eTweenRegionLightLevel) {
    this.regionRef.LightLevel = Lerp(this.fromX, this.toX, amount);
  }
  else if (this.type == _eTweenRegionTintR) {
    int saturation = this.regionRef.TintSaturation;
    if (saturation < 0) saturation = 0;      
    this.regionRef.Tint(Lerp(this.fromX, this.toX, amount), this.regionRef.TintGreen, this.regionRef.TintBlue, saturation);
  }
  else if (this.type == _eTweenRegionTintG) {
    int saturation = this.regionRef.TintSaturation;
    if (saturation < 0) saturation = 0;      
    this.regionRef.Tint(this.regionRef.TintRed, Lerp(this.fromX, this.toX, amount), this.regionRef.TintBlue, saturation); 
  }
  else if (this.type == _eTweenRegionTintB) {
    int saturation = this.regionRef.TintSaturation;
    if (saturation < 0) saturation = 0;      
    this.regionRef.Tint(this.regionRef.TintRed, this.regionRef.TintGreen, Lerp(this.fromX, this.toX, amount), saturation);
  }
  else if (this.type == _eTweenRegionTintAmount) {
    int saturation = Lerp(this.fromX, this.toX, amount);
    if (saturation < 0) saturation = 0;      
    this.regionRef.Tint(this.regionRef.TintRed, this.regionRef.TintGreen, this.regionRef.TintBlue, saturation);
  }
  /// LABEL step  
  else if (this.type == _eTweenLabelPosition) {
    this.labelRef.SetPosition(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
  }
  else if (this.type == _eTweenLabelSize) {
    this.labelRef.SetSize(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
  }
  else if (this.type == _eTweenLabelColorR) {
    this.labelRef.TextColor = Game.GetColorFromRGB(Lerp(this.fromX, this.toX, amount), GetGFromColor(this.labelRef.TextColor), GetBFromColor(this.labelRef.TextColor));
  }
  else if (this.type == _eTweenLabelColorG) {
    this.labelRef.TextColor = Game.GetColorFromRGB(GetRFromColor(this.labelRef.TextColor), Lerp(this.fromX, this.toX, amount), GetBFromColor(this.labelRef.TextColor));
  }
  else if (this.type == _eTweenLabelColorB) {
    this.labelRef.TextColor = Game.GetColorFromRGB(GetRFromColor(this.labelRef.TextColor), GetGFromColor(this.labelRef.TextColor), Lerp(this.fromX, this.toX, amount));
  }
  /// BUTTON step
  else if (this.type == _eTweenButtonPosition) {
    this.buttonRef.SetPosition(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
  }
  else if (this.type == _eTweenButtonSize) {
    this.buttonRef.SetSize(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
  }
  else if (this.type == _eTweenButtonColorR) {
    this.buttonRef.TextColor = Game.GetColorFromRGB(Lerp(this.fromX, this.toX, amount), GetGFromColor(this.buttonRef.TextColor), GetBFromColor(this.buttonRef.TextColor));
  }
  else if (this.type == _eTweenButtonColorG) {
    this.buttonRef.TextColor = Game.GetColorFromRGB(GetRFromColor(this.buttonRef.TextColor), Lerp(this.fromX, this.toX, amount), GetBFromColor(this.buttonRef.TextColor));
  }
  else if (this.type == _eTweenButtonColorB) {
    this.buttonRef.TextColor = Game.GetColorFromRGB(GetRFromColor(this.buttonRef.TextColor), GetGFromColor(this.buttonRef.TextColor), Lerp(this.fromX, this.toX, amount));
  }
  /// TEXTBOX step
  else if (this.type == _eTweenTextBoxPosition) {
    this.textBoxRef.SetPosition(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
  }
  else if (this.type == _eTweenTextBoxSize) {
    this.textBoxRef.SetSize(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
  }
  else if (this.type == _eTweenTextBoxColorR) {
    this.textBoxRef.TextColor = Game.GetColorFromRGB(Lerp(this.fromX, this.toX, amount), GetGFromColor(this.textBoxRef.TextColor), GetBFromColor(this.textBoxRef.TextColor));
  }
  else if (this.type == _eTweenTextBoxColorG) {
    this.textBoxRef.TextColor = Game.GetColorFromRGB(GetRFromColor(this.textBoxRef.TextColor), Lerp(this.fromX, this.toX, amount), GetBFromColor(this.textBoxRef.TextColor));
  }
  else if (this.type == _eTweenTextBoxColorB) {
    this.textBoxRef.TextColor = Game.GetColorFromRGB(GetRFromColor(this.textBoxRef.TextColor), GetGFromColor(this.textBoxRef.TextColor), Lerp(this.fromX, this.toX, amount));
  }
  /// LISTBOX step
  else if (this.type == _eTweenListBoxPosition) {
    this.listBoxRef.SetPosition(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
  }
  else if (this.type == _eTweenListBoxSize) {
    this.listBoxRef.SetSize(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
  }
  else if (this.type == _eTweenListBoxSelectedItem) {
    this.listBoxRef.SelectedIndex =  Lerp(this.fromX, this.toX, amount);
  }
  else if (this.type == _eTweenListBoxTopItem) {
    this.listBoxRef.TopItem = Lerp(this.fromX, this.toX, amount);
  }
  /// SLIDER step
  else if (this.type == _eTweenSliderPosition) {
    this.sliderRef.SetPosition(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
  }
  else if (this.type == _eTweenSliderSize) {
    this.sliderRef.SetSize(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
  }
  else if (this.type == _eTweenSliderValue) {
    this.sliderRef.Value =  Lerp(this.fromX, this.toX, amount);
  }
  else if (this.type == _eTweenSliderHandleOffset) {
    this.sliderRef.HandleOffset = Lerp(this.fromX, this.toX, amount);
  }
  /// INVWINDOW step
  else if (this.type == _eTweenInvWindowPosition) {
    this.invWindowRef.SetPosition(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
  }
  else if (this.type == _eTweenInvWindowSize) {
    this.invWindowRef.SetSize(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
  }
  else if (this.type == _eTweenInvWindowTopItem) {
    this.invWindowRef.TopItem = Lerp(this.fromX, this.toX, amount);
  }
  /// MISC step
  else if (this.type == _eTweenViewportX) {
    SetViewport(Lerp(this.fromX, this.toX, amount), GetViewportY());   
  }
  else if (this.type == _eTweenViewportY) {
    SetViewport(GetViewportX(), Lerp(this.fromY, this.toY, amount));   
  }
  else if (this.type == _eTweenViewportXY) {
    SetViewport(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));   
  }
  else if (this.type == _eTweenGamma) {   
    System.Gamma = Lerp(this.fromX, this.toX, amount);       
  }
  else if (this.type == _eTweenMusicMasterVolume) {
    SetMusicMasterVolume(Lerp(this.fromX, this.toX, amount));
  }
  else if (this.type == _eTweenDigitalMasterVolume) {
    int volume = Lerp(this.fromX, this.toX, amount);
    //Display("%d", volume);
    SetDigitalMasterVolume(volume/*Lerp(this.fromX, this.toX, amount)*/);
  }
  else if (this.type == _eTweenSoundVolume) {
    SetSoundVolume(Lerp(this.fromX, this.toX, amount));
  }
  else if (this.type == _eTweenSpeechVolume) {
    SetSpeechVolume(Lerp(this.fromX, this.toX, amount));
  }
  else if (this.type == _eTweenChannelVolume) {
    SetChannelVolume(this.extraParam1, Lerp(this.fromX, this.toX, amount));
  }
  else if (this.type == _eTweenShakeScreen) {
    ShakeScreenBackground(Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount), 1);
  }  
  else if (this.type == _eTweenAreaScaling) {
    SetAreaScaling(this.extraParam1, Lerp(this.fromX, this.toX, amount), Lerp(this.fromY, this.toY, amount));
  }
}

void ResetAndStopAllTweens() {
  short i = 0;
  
  while (i < MAX_TWEENS) {
    if (_tweens[i].duration != -1) {
      _tweens[i].step(0.0);
      _tweens[i].duration = -1;
    }
    
    i++;
  }
}

///////////////////////////////////////////////////////////////////////////////

function game_start() {
  short i = 0;
  
  while (i < MAX_TWEENS) {
    _tweens[i].duration = -1;
    i++;
  }
    
  System.VSync = true;
}

// This is where the magic happens:
function repeatedly_execute_always() {
  short i = 0;
  
  while (i < MAX_TWEENS) {
		if (_tweens[i].duration > 0) {
			float amount = ComputeTiming(
				_tweens[i].frameCount,
				_tweens[i].duration,
				_tweens[i].timing
				);
			
			_tweens[i].step(amount);
			
			_tweens[i].frameCount++;
			
			if (_tweens[i].frameCount > _tweens[i].duration) {
			  if (_tweens[i].style == eRepeatTween) {
					_tweens[i].frameCount = 0;
			  }
			  else if (_tweens[i].style == eReverseRepeatTween) {
					short fromX = _tweens[i].toX;
					short fromY = _tweens[i].toY;
					
					_tweens[i].toX = _tweens[i].fromX;
					_tweens[i].toY = _tweens[i].fromY;
					_tweens[i].fromX = fromX;
					_tweens[i].fromY = fromY;
					
					_tweens[i].frameCount = 0;
        }
				else {
					_tweens[i].duration = -1;
				}
			}
		}
		
		i++;
	}
}

function on_event(EventType event, int data) {
  if (event == eEventLeaveRoom) {
    ResetAndStopAllTweens();
  }
}